#-*- encoding:utf8 -*-

from django.db import models as db_models
from django import forms as django_forms
from django.template.loader import get_template,Context
import json
from tools import tools
from base import actions,columns,searchers

FIELD = db_models.fields.Field
field_old_init = FIELD.__init__
field_old_formfield = FIELD.formfield

#　扩展Field.__init__方法
def set_field_init():
    def new_field_init(self,widget_attrs={},column_template_name=None,search_template_name=None,edit_template_name=None,*args,**kwargs):
        field_old_init(self,*args,**kwargs)
        self.widget_attrs = widget_attrs
        self.column_template_name = column_template_name
        self.search_template_name = search_template_name
        self.edit_template_name = edit_template_name

    FIELD.__init__ = new_field_init

set_field_init()

# 扩展Ｆield.formfield方法
# def set_field_formfield():
#     def new_field_formfield(self,form_class=None,choices_form_class=None,**kwargs):
#         form_class = form_class if form_class else self.form_class
#         formfield = field_old_formfield(self,form_class,choices_form_class,**kwargs)
#         # 设置formfield.widget.attrs的值，在输出时控制html的属性
#         if self.widget_attrs is not None:
#             formfield.widget.attrs.update(self.widget_attrs)
#         return formfield

    # FIELD.formfield = new_field_formfield

# set_field_formfield()

def set_field_widget():
    def widget(self,is_search=False):
        template = self.get_widget_template()
        context = self.get_widget_context(is_search)
        return template.render(context)

    setattr(FIELD,u'get_widget',widget)

    def get_widget_template(self):
        return tools.Import.get_field_template(self.model.school_get_model_full_name(),u'%s.html'%self.name.lower(),u'base/widgets/%s.html'%self.__class__.__name__.lower())

    def get_widget_context(self,is_search):
        return Context({
                u'field':self,
                u'is_search' : is_search
        })

    setattr(FIELD,u'get_widget_template',get_widget_template)
    setattr(FIELD,u'get_widget_context',get_widget_context)

set_field_widget()

# 扩展Field加入column的相关方法，供前端生datatable时定义列时的模板
def add_method_column():
    # 用于datatable定义列时使用
    def column_render(self):
        try:
            return self.get_column_template().render(self.get_column_context())
        except:
            return json.dumps({u'data':self.name})
    setattr(FIELD,u'column_render',column_render)

    def get_column_template(self):
        template = tools.Import.get_field_template(self.model.school_get_model_full_name(),u'columns/%s.html'%self.name.lower(),u'base/columns/%s.html'%self.__class__.__name__.lower())
        return template
        # if self.column_template_name:
        #     template_name = self.column_template_name is self.column_template_name
        # else:
        #     template_name = u'base/columns/%s.html'%self.__class__.__name__.lower()
        # return get_template(template_name)

    setattr(FIELD,u'get_column_template',get_column_template)

#6217992610097527485+

    def get_column_context(self):
        return Context({u'field' : self})

    setattr(FIELD,u'get_column_context',get_column_context)

add_method_column()

########################################################################
#
# 定义数据筛选时列支持的方法
#
########################################################################

def add_method_search():
    # 扩展Field加入search_render的方法，供前端生datatable时筛选数据时的使用
    def search_render(self):
        return self.get_widget(True)

    setattr(FIELD,u'search_render',search_render)

    # def get_search_template(self):
    #     if self.search_template_name:
    #         template_name = self.search_template_name
    #     else:
    #         template_name = u'base/searchers/%s.html'%self.__class__.__name__.lower()
    #     return get_template(template_name)
    #
    #
    # setattr(FIELD,u'get_search_template',get_search_template)
    #
    #
    # def get_search_context(self):
    #     return Context({u'field' : self})

    # setattr(FIELD,u'get_search_context',get_search_context)

    def search(self,request,records):
        value = request.POST.get(self.name,None)
        if not value:
            return records
        q = db_models.Q()
        q.children.append((self.name,value))
        return records.filter(q)

    setattr(FIELD,u'search',search)

    # 设置BooleanField.search
    # 设置CharFieldField.search
    # 设置ForeignKey.search
    # 其它字段，据实际改写...

add_method_search()


#####################################################################################
#
# BooleanField
#
#####################################################################################

def boolean_add_method():
    def search(self,request,records):
        value = request.POST.get(self.name,None)
        if value==u'true':
            value = True
        elif value==u'false':
            value = False
        else:
            value = None

        if value is None:
            return records
        q = db_models.Q()
        q.children.append((self.name,value))
        return records.filter(q)

    setattr(db_models.BooleanField,u'search',search)

boolean_add_method()
#####################################################################################
#
# CharField
#
#####################################################################################

def charfield_add_method():
    def search(self,request,records):
        value = request.POST.get(self.name,None)
        if not value:
            return records
        q = db_models.Q()
        q.children.append((self.name+'__icontains',value))
        return records.filter(q)

    setattr(db_models.CharField,u'search',search)

charfield_add_method()
#####################################################################################
#
# ForeignKey
#
#####################################################################################

def foreignkey_add_method():
    def search_context(self,request):
        role_name = request.path.split(u'/')[-2]
        main_model_by_role = tools.load_member(self.request,self.rel.to.school_get_model_full_name(),role_name)
        try:
            # 该字段所在数据模型定义了foreignkey_records_filter_（字段名）(request)方法
            #　使用该方法过滤数据
            filter_method = getattr(self.field.model,u'foreignkey_records_filter_%s'%self.field.name)
            records = filter_method(self.request)
        except:
            #　出现异常，使用该字段关联的数据模型的filter(request)方法
            records = main_model_by_role.school_filter(self.request)
        records = main_model_by_role.school_items(records)
        return Context({
            u'request' : self.request,
            u'field' : self.field,
            u'options' : records
        })

    setattr(db_models.ForeignKey,u'search_context',search_context)

    def search(self,request,records):
        value = request.POST.get(self.name)
        if value:
            try:
                method = getattr(self.field.model,u'searchforeignkey_%s'%self.field.name)
                records = method(self.request,records)
            except:
                q = db_models.Q()
                q.children.append((u'%s__pk'%self.name,value))
                records = records.filter(q)

        return records

    setattr(db_models.ForeignKey,u'search',search)

foreignkey_add_method()


####################################################################
#
# Edit编辑功能实现
#
####################################################################

def add_method_edit():
    def edit_unique(self):
        result = {u'type':u'get'}
        result[u'url'] = u'/validator/%s/%s/'%(self.field.model.path(),self.name)
        result[u'cache'] = False
        result[u'async'] = False
        return result

    def edit_rules(self):
        result = {}
        if self.required():
            result[u'required'] = True
        if self.__unique:
            result[u'remote']  = self.unique()
        return result

    def edit_validate_rules(self):
        return json.dumps(self.rules())

    def edit_required(self):
        return not (self.field.null and self.field.blank)

    def edit_render(self):
        return self.get_widget(is_search=False)

    setattr(FIELD,u'edit_unique',edit_unique)
    setattr(FIELD,u'edit_rules',edit_rules)
    setattr(FIELD,u'edit_required',edit_required)
    setattr(FIELD,u'edit_edit_validate_rules',edit_validate_rules)
    setattr(FIELD,u'edit_render',edit_render)

add_method_edit()

# 以上是扩展Field的Ｅdit功能，需要进一步完善

class ModelMetaClass(type):
    def __new__(cls,name,bases,attrs):
        module = attrs.pop('__module__')
        parents = [b for b in bases if isinstance(b, ModelMetaClass)]
        if parents:
            for obj_name, obj in attrs.items():
                db_models.Model.add_to_class(obj_name, obj)
        return super(ModelMetaClass, cls).__new__(cls, name, bases, attrs)

class SchoolModelBase(object):
    __metaclass__ = ModelMetaClass

class SchoolModel(SchoolModelBase):
    #######################################################
    #
    # SchoolModel.py
    # Python implementation of the Class SchoolModel
    # Generated by Enterprise Architect
    # Created on:      12-四月-2016 16:50:20
    #
    #######################################################

    SCHOOL_MANAGEABLE = False
    SCHOOL_PRIMARY_KEY_NAME = u'id'
    SCHOOL_SCHOOL_FIELD_NAME = None

    SCHOOL_ACTIONS = [u'create',u'edit',u'delete',u'print']

    """通过python动态类特性，扩展django.db.models.Model类，以配合前端Web的操作,
      约定所有的属性和方法都以school[SCHOOL]开始。
    """
    @classmethod
    def school_get_role_name(cls, request):
        """类方法，返回当前用户访问时，使用的角色名称
        """
        return request.path.split(u'/')[-2]

    @classmethod
    def school_datas(cls, request):
        """类方法，Web数据表请求数据时调用Model的这个方法
        """
        post_data = tools.Tools.analysis_datatable_post(request)

        records = cls.school_filter(request)

        total_count = records.count()

        for field in cls.school_get_columns(request):
            records = field.search(records)

        filter_count = records.count()

        sorting = []
        for index in range(len(post_data[u'orders'].keys())):
            name = post_data[u'orders'][unicode(index)][u'name']
            name = name.split(".")[0]
            direction = post_data[u'orders'][unicode(index)][u'dir']
            if direction == u'desc':
                name = u'-' + name
            sorting.append(name)

        records = records.order_by(*sorting)

        length = int(post_data[u'length'])
        start = int(post_data[u'start'])
        if length<>-1:
            result = cls.school_rows(request,records[start:(start+length)])
        else :
            result = cls.rows(request,records)

        result[u'draw'] = post_data[u"draw"]
        result[u'recordsFiltered'] = filter_count
        result[u'recordsTotal'] = total_count
        return result

    @classmethod
    def school_rows(cls, request, records):
        """类方法，将一个数据集中的所有数据通过调用school_row方法转换成一个列表并返回
        """
        data = []
        fields = cls.school_get_columns(request)
        for record in records:
            data.append(record.school_row(request,fields))

        return {
            u'data':data
        }
        pass

    def school_row(self, request, fields):
        """实例方法，将一行记录转换成相应的字典，返回
        """
        result = {}
        for field in fields:
            result[field.name] = field.val_from_obj(self)
        result[u'id'] = getattr(self,self.SCHOOL_PRIMARY_KEY_NAME)
        return result

    @classmethod
    def school_get_search_fields(cls, request):
        """类方法，返回在在前端Web页面中筛选表格中数据时的域，不同角色改写
        """
        return [columns.Searcher(request,field) for field in cls._meta.fields[1:10]]

    @classmethod
    def school_get_edit_fields(cls, request):
        """类方法，返回在在前端Web页面中编辑表格中数据时的编辑哉，不同角色改写
        """
        pass

    @classmethod
    def school_get_actions(cls, request,obj_pk):
        """类方法，返回在前端Web页面数据表格中可以进行的操作，不同角色改写
        """
        #return [actions.Action(action.action.identity,action.action.text,cls) for action in request.user.get_objects_by_group().get(object__pk=obj_pk).object.groupaction_set.all()]
        return [actions.Action(request,cls,action) for action in cls.SCHOOL_ACTIONS]

    @classmethod
    def school_save_instance(cls, request, action):
        """类方法，将一个数据集中的所有数据通过调用school_row方法转换成一个列表并返回
        """
        pass

    @classmethod
    def school_get_js_path(cls):
        """类方法，返回模板中使用的javascript文件名称
        """
        pass

    @classmethod
    def school_filter(cls, request):
        """类方法，根据当前用户角色过滤数据，这个方法需要根据角色进行改写。
        """
        records = cls.objects.all()
        if cls.SCHOOL_SCHOOL_FIELD_NAME:
            q = db_models.Q()
            q.children.append((cls.SCHOOL_SCHOOL_FIELD_NAME,getattr(request.user,request.user.SCHOOL_SCHOOL_FIELD_NAME)))
            records = records.filter(q)
        return records

    @classmethod
    def school_get_context(cls, request,obj_pk):
        """类方法，返回一渲染模板的上下文
        """
        return Context({
            u'actions' : cls.school_get_actions(request,obj_pk),
            u'columns' : cls.school_get_columns(request),
            u'searchers' : cls.school_get_search_fields(request),
            u'model_verbose_name' : cls._meta.verbose_name,
            u'model_name' : cls.__class__.__name__,
            u'grid_name' : cls.school_get_grid_name()
        })
        pass

    @classmethod
    def school_get_grid_name(cls):
        return cls.school_get_model_full_name().replace(u'.',u'_')

    @classmethod
    def school_get_template(cls,request):
        """类方法，返回一个模板，根据当前Model的完整路径，分别在不同路径下寻找相应的模板文件，具体查找如下：
           1、查找APP/ROLES/role/templates/models/MODEL.low()+'.html'模板文件,找到后返回。
           2、否则，查找APP/ROLES/templates/models/MODEL.low()+'.html'模板文件,找到后返回。
           3、否则，查找APP/templates/models/MODEL.low()+'.html'模板文件,找到后返回。
           4、否则，查找APP/templates/models/MODEL.low()+'.html'模板文件,找到后返回。
        """
        path = cls.school_get_model_full_name().split(u'.')
        del path[-2]
        while len(path)>=2:
            try:
                return get_template(u'/'.join(path).lower())
            except:
                del path[-2]
        return get_template(u'base/grid.html')

    @classmethod
    def school_get_model_full_name(cls):
        """类方法，返回一个类的完整路径名称，以点分隔。
        """
        return u'%s.%s'%(cls.__module__,cls.__name__)

    def school_item(self):
        """实例方法，将一条记录转换成名-值对的字典，为生成前端树需要的数据做准备
        """
        return {u"id":getattr(self,self.SCHOOL_PRIMARY_KEY_NAME),u"name":unicode(self)}

    @classmethod
    def school_items(cls, records):
        """类方法，将一个数据集中的所有记录转换成一个列表，为生成前端树需要的数据做准备
        """
        result = []
        for record in records:
            result.append(record.school_item())
        return result

    @classmethod
    def school_ajax_tree_items(cls,request,parent,level):
        """类方法，如果一个类提供以Web树显示当前内容，可以实现该方法，根据参数的情况进行定义
        """
        role_name = cls.school_get_role_name(request)
        return {
            u'id':'1',
            u'text':u'%s对象还没有实现读取节点的方法。'%cls.school_get_model_full_name(),
            u'children':True
        }

    @classmethod
    def school_get_columns(cls, request):
        """类方法，返回在前端Web页面数据表格中显示的列，不同角色改写
        """
        return [columns.Column(request,field) for field in cls._meta.fields[1:10]]

    def school_do_action_create(cls, request):
        """类方法，完成创建操作时的默认方法
        """
        pass

    @classmethod
    def school_do_action_delete(cls, request):
        """类方法，完成创移除数据操作时的默认方法
        """
        pass

    @classmethod
    def school_do_action_edit(cls, request):
        """类方法，完成创编辑数据操作时的默认方法
        """
        pass

    @classmethod
    def school_do_action(cls, request):
        """类方法，前端提交一个操作，调用这个方法进行分派，找到相应的具体的操作，要求在提交参数中至少要有action这个域，指明相应的操作，这个类同时要定义school_
        action_[action域指定的值]这样一个静态方法。示例如下：
           def do_school_action_create(cls,request):
                pass
           要求action域指定的值为create
        """
        action = request.POST.get(u'action')
        return getattr(cls,u'school_do_action_%s'%action)(request)